Laura Stickells

November 8, 2020

library(nflfastR)
library(tidyverse)
library(xlsx)
library(ggplot2)
library(dplyr)
library(ggimage)
library(ggthemes)
library(scales)
library(DT)

Load play by play data

pbp20 <- readRDS(url('https://raw.githubusercontent.com/guga31bb/nflfastR-data/master/data/play_by_play_2020.rds'))
pbp19 <- readRDS(url('https://raw.githubusercontent.com/guga31bb/nflfastR-data/master/data/play_by_play_2019.rds'))

#Takes about 45 seconds
seasons <- 1999:2020
pbp <- map_df(seasons, function(x) {
  readRDS(url(paste0("https://raw.githubusercontent.com/guga31bb/nflfastR-data/master/data/play_by_play_",x,".rds")))
})

Ball security and sacks by quarterback. Percentages calculated based on total number of dropbacks including sacks and scrambles. (turnover percentage, total turnovers, interception percentage, total interceptions, quarterback fumble percentage, total quarterback fumbles, quarterback fumbles lost percentage, total quarterback fumbles lost, sack percentage, total sacks, number of dropbacks )

to_pct <- pbp %>%
  filter(season == 2020, epa != 0, passer != 'NA') %>%
  mutate(
    qb_fumble = case_when(
      fumbled_1_player_name == passer ~ 1,
      fumbled_1_player_name != passer ~ 0,
      is.na(fumbled_1_player_name) ~ 0
    ),
    qb_fumble_lost = case_when(
      qb_fumble == 1 & fumble_lost == 1 ~ 1,
      TRUE ~ 0
    )
  ) %>%
  group_by(passer, passer_id) %>% 
  summarize(
    to_pct = round((mean(interception)+mean(qb_fumble_lost))*100, digits = 2),
    to = sum(interception)+sum(qb_fumble_lost),
    int_pct = round(mean(interception)*100, digits = 2),
    int = sum(interception),
    fum_pct = round(mean(qb_fumble)*100, digits = 2),
    fum = sum(qb_fumble),
    fum_lost_pct = round(mean(qb_fumble_lost)*100, digits = 2),
    fum_lost = sum(qb_fumble_lost),
    sack_pct = round(mean(sack)*100, digits = 2),
    sacks = sum(sack),
    plays = n(),
  )  %>%
  select(-passer_id) %>%
  filter(plays >= 100) %>%
  arrange(to_pct)
`summarise()` regrouping output by 'passer' (override with `.groups` argument)
table <- datatable(to_pct,
          caption = 'Daniel Jones is highlighted in yellow. Data from NFLfastR.',
          colnames = c("", "Quarterback", "Turnover\nPercentage", "Turnovers", "Interception\nPercentage", "Interceptions", "Fumble\nPercentage", "Fumbles", "Fumbles\nLost\nPercentage", "Fumbles\nLost", "Sack\nPercentage", "Sacks", "Dropbacks"),
          options = list(scrollX = TRUE),
          width = 800,
          class = 'cell-border stripe'
          ) %>% 
  formatStyle(
  'passer',
  target = 'row',
  backgroundColor = styleEqual(c('D.Jones'), c('lightyellow'))
)

table

NA

I switched out Daniel Jones for a few other QBs (Russell Wilson, Tom Brady, Aaron Rodgers and Drew Lock) to make sure different QBs had distinct enough plots to be making observations.

quarterback_dropbacks <- pbp %>%
  mutate(
    passer = case_when(
      passer == 'D.Jones' ~ 'Daniel Jones',
      passer != 'D.Jones' ~ 'Other QBs'
      ),
    passer = factor(passer)
  ) %>%
  filter(cp != 'NA', season == 2020) %>%
  select(cp, interception, passer, week)

interceptions_only <- quarterback_dropbacks %>%
  filter(interception == 1, passer == 'Daniel Jones')

quarterback_dropbacks %>%
  ggplot(aes(x= cp, fill = passer)) +
  geom_density(alpha = .7) +
  geom_rug(data = interceptions_only, aes(x = cp, y = 0, color = passer), position = position_jitter(height = 0), show.legend = F, length = unit(0.05, "npc")) +
  ggthemes::theme_fivethirtyeight() +
  theme(
    legend.position = "bottom",
    legend.title = element_blank(),
    strip.text = element_text(face = "bold"),
    axis.title = element_text()
    ) +
  labs(
    x = "Completion Probability",
    y = "Density",
    title = "Distribution of Daniel Jones' completion probability\ncompared to the rest of the league",
    subtitle = "Interceptions are represented as red tick marks on the x-axis",
    caption = "Data: @nflfastR | Plot: @LauraStickells"
  )

A linear model using league wide completion probability to predict interceptions. I didn’t do any predictive analysis, so I don’t expect these models to perfectly predict future interceptions. I was using them more to understand the past relationship between completion probability and interceptions with a Y-intercept.

passers <- pbp20 %>%
  filter(passer != 'NA', cp != 'NA')
passers_model <- lm(passers$interception ~ passers$cp)
summary.lm(passers_model)

Call:
lm(formula = passers$interception ~ passers$cp)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.07235 -0.03250 -0.01713 -0.00975  1.00061 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept)  0.089785   0.006688   13.43   <2e-16 ***
passers$cp  -0.100129   0.009734  -10.29   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1494 on 8125 degrees of freedom
Multiple R-squared:  0.01286,   Adjusted R-squared:  0.01273 
F-statistic: 105.8 on 1 and 8125 DF,  p-value: < 2.2e-16

A linear model using Daniel Jones’ completion probability to predict interceptions.

daniel_jones <- pbp20 %>%
  filter(passer == 'D.Jones', cp != 'NA')
daniel_jones_model <- lm(daniel_jones$interception ~ daniel_jones$cp)
summary.lm(daniel_jones_model)

Call:
lm(formula = daniel_jones$interception ~ daniel_jones$cp)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.11734 -0.04964 -0.02381 -0.01149  0.99399 

Coefficients:
                Estimate Std. Error t value Pr(>|t|)   
(Intercept)      0.16841    0.05172   3.256  0.00128 **
daniel_jones$cp -0.19765    0.07476  -2.644  0.00871 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1821 on 255 degrees of freedom
Multiple R-squared:  0.02668,   Adjusted R-squared:  0.02286 
F-statistic:  6.99 on 1 and 255 DF,  p-value: 0.008705

Graphing the two linear models against eachother.

passers$model <- "League Average"
daniel_jones$model <- "Daniel Jones"

linear_models <- rbind(passers, daniel_jones)

ggplot(linear_models, aes(x = cp, y = interception, group=model, color =model)) + 
  stat_smooth(method = "lm", geom = "line", alpha = 0.5, se = FALSE, size = 1) +
  ggthemes::theme_fivethirtyeight() +
  theme(
    legend.position = "bottom",
    legend.title = element_blank(),
    strip.text = element_text(face = "bold"),
    axis.title = element_text()
    ) +
  labs(
    x = "Completion Probability",
    y = "Interception Probability",
    title = "Correlation between completion probability\nand interceptions",
    subtitle = "",
    caption = "Data: @nflfastR | Plot: @LauraStickells"
  )

This table calculating the correlation between completion probability and interceptions doesn’t mean much without looking at the y-intercepts, but the results provide some interesting insights, which could be an interesting area for future exploration.

pbp20 %>%
  filter(passer != 'NA', cp != 'NA') %>%
  group_by(passer) %>%
  summarize(
    cor = cor(cp, interception), 
    plays = n(), 
  ) %>%
  filter(plays >= 100) %>%
  arrange(cor) %>%
  ungroup()
the standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zerothe standard deviation is zero`summarise()` ungrouping output (override with `.groups` argument)

LS0tCnRpdGxlOiAiTkZMIEJsb2cgMjogQW5hbHl6aW5nIERhbmllbCBKb25lcycgZGVjaXNpb24gbWFraW5nIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCiMjIyMgTGF1cmEgU3RpY2tlbGxzCiMjIyMgTm92ZW1iZXIgOCwgMjAyMAoKYGBge3J9CmxpYnJhcnkobmZsZmFzdFIpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHhsc3gpCmxpYnJhcnkoZ2dwbG90MikKbGlicmFyeShkcGx5cikKbGlicmFyeShnZ2ltYWdlKQpsaWJyYXJ5KGdndGhlbWVzKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKYGBgCiMKTG9hZCBwbGF5IGJ5IHBsYXkgZGF0YQpgYGB7cn0KcGJwMjAgPC0gcmVhZFJEUyh1cmwoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ndWdhMzFiYi9uZmxmYXN0Ui1kYXRhL21hc3Rlci9kYXRhL3BsYXlfYnlfcGxheV8yMDIwLnJkcycpKQpwYnAxOSA8LSByZWFkUkRTKHVybCgnaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2d1Z2EzMWJiL25mbGZhc3RSLWRhdGEvbWFzdGVyL2RhdGEvcGxheV9ieV9wbGF5XzIwMTkucmRzJykpCgojVGFrZXMgYWJvdXQgNDUgc2Vjb25kcwpzZWFzb25zIDwtIDE5OTk6MjAyMApwYnAgPC0gbWFwX2RmKHNlYXNvbnMsIGZ1bmN0aW9uKHgpIHsKICByZWFkUkRTKHVybChwYXN0ZTAoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9ndWdhMzFiYi9uZmxmYXN0Ui1kYXRhL21hc3Rlci9kYXRhL3BsYXlfYnlfcGxheV8iLHgsIi5yZHMiKSkpCn0pCmBgYAoKIwpCYWxsIHNlY3VyaXR5IGFuZCBzYWNrcyBieSBxdWFydGVyYmFjay4gUGVyY2VudGFnZXMgY2FsY3VsYXRlZCBiYXNlZCBvbiB0b3RhbCBudW1iZXIgb2YgZHJvcGJhY2tzIGluY2x1ZGluZyBzYWNrcyBhbmQgc2NyYW1ibGVzLiAodHVybm92ZXIgcGVyY2VudGFnZSwgdG90YWwgdHVybm92ZXJzLCBpbnRlcmNlcHRpb24gcGVyY2VudGFnZSwgdG90YWwgaW50ZXJjZXB0aW9ucywgcXVhcnRlcmJhY2sgZnVtYmxlIHBlcmNlbnRhZ2UsIHRvdGFsIHF1YXJ0ZXJiYWNrIGZ1bWJsZXMsIHF1YXJ0ZXJiYWNrIGZ1bWJsZXMgbG9zdCBwZXJjZW50YWdlLCB0b3RhbCBxdWFydGVyYmFjayBmdW1ibGVzIGxvc3QsIHNhY2sgcGVyY2VudGFnZSwgdG90YWwgc2Fja3MsIG51bWJlciBvZiBkcm9wYmFja3MgKQpgYGB7cn0KdG9fcGN0IDwtIHBicCAlPiUKICBmaWx0ZXIoc2Vhc29uID09IDIwMjAsIGVwYSAhPSAwLCBwYXNzZXIgIT0gJ05BJykgJT4lCiAgbXV0YXRlKAogICAgcWJfZnVtYmxlID0gY2FzZV93aGVuKAogICAgICBmdW1ibGVkXzFfcGxheWVyX25hbWUgPT0gcGFzc2VyIH4gMSwKICAgICAgZnVtYmxlZF8xX3BsYXllcl9uYW1lICE9IHBhc3NlciB+IDAsCiAgICAgIGlzLm5hKGZ1bWJsZWRfMV9wbGF5ZXJfbmFtZSkgfiAwCiAgICApLAogICAgcWJfZnVtYmxlX2xvc3QgPSBjYXNlX3doZW4oCiAgICAgIHFiX2Z1bWJsZSA9PSAxICYgZnVtYmxlX2xvc3QgPT0gMSB+IDEsCiAgICAgIFRSVUUgfiAwCiAgICApCiAgKSAlPiUKICBncm91cF9ieShwYXNzZXIsIHBhc3Nlcl9pZCkgJT4lIAogIHN1bW1hcml6ZSgKICAgIHRvX3BjdCA9IHJvdW5kKChtZWFuKGludGVyY2VwdGlvbikrbWVhbihxYl9mdW1ibGVfbG9zdCkpKjEwMCwgZGlnaXRzID0gMiksCiAgICB0byA9IHN1bShpbnRlcmNlcHRpb24pK3N1bShxYl9mdW1ibGVfbG9zdCksCiAgICBpbnRfcGN0ID0gcm91bmQobWVhbihpbnRlcmNlcHRpb24pKjEwMCwgZGlnaXRzID0gMiksCiAgICBpbnQgPSBzdW0oaW50ZXJjZXB0aW9uKSwKICAgIGZ1bV9wY3QgPSByb3VuZChtZWFuKHFiX2Z1bWJsZSkqMTAwLCBkaWdpdHMgPSAyKSwKICAgIGZ1bSA9IHN1bShxYl9mdW1ibGUpLAogICAgZnVtX2xvc3RfcGN0ID0gcm91bmQobWVhbihxYl9mdW1ibGVfbG9zdCkqMTAwLCBkaWdpdHMgPSAyKSwKICAgIGZ1bV9sb3N0ID0gc3VtKHFiX2Z1bWJsZV9sb3N0KSwKICAgIHNhY2tfcGN0ID0gcm91bmQobWVhbihzYWNrKSoxMDAsIGRpZ2l0cyA9IDIpLAogICAgc2Fja3MgPSBzdW0oc2FjayksCiAgICBwbGF5cyA9IG4oKSwKICApICAlPiUKICBzZWxlY3QoLXBhc3Nlcl9pZCkgJT4lCiAgZmlsdGVyKHBsYXlzID49IDEwMCkgJT4lCiAgYXJyYW5nZSh0b19wY3QpCgp0YWJsZSA8LSBkYXRhdGFibGUodG9fcGN0LAogICAgICAgICAgY2FwdGlvbiA9ICdEYW5pZWwgSm9uZXMgaXMgaGlnaGxpZ2h0ZWQgaW4geWVsbG93LiBEYXRhIGZyb20gTkZMZmFzdFIuJywKICAgICAgICAgIGNvbG5hbWVzID0gYygiIiwgIlF1YXJ0ZXJiYWNrIiwgIlR1cm5vdmVyXG5QZXJjZW50YWdlIiwgIlR1cm5vdmVycyIsICJJbnRlcmNlcHRpb25cblBlcmNlbnRhZ2UiLCAiSW50ZXJjZXB0aW9ucyIsICJGdW1ibGVcblBlcmNlbnRhZ2UiLCAiRnVtYmxlcyIsICJGdW1ibGVzXG5Mb3N0XG5QZXJjZW50YWdlIiwgIkZ1bWJsZXNcbkxvc3QiLCAiU2Fja1xuUGVyY2VudGFnZSIsICJTYWNrcyIsICJEcm9wYmFja3MiKSwKICAgICAgICAgIG9wdGlvbnMgPSBsaXN0KHNjcm9sbFggPSBUUlVFKSwKICAgICAgICAgIHdpZHRoID0gODAwLAogICAgICAgICAgY2xhc3MgPSAnY2VsbC1ib3JkZXIgc3RyaXBlJwogICAgICAgICAgKSAlPiUgCiAgZm9ybWF0U3R5bGUoCiAgJ3Bhc3NlcicsCiAgdGFyZ2V0ID0gJ3JvdycsCiAgYmFja2dyb3VuZENvbG9yID0gc3R5bGVFcXVhbChjKCdELkpvbmVzJyksIGMoJ2xpZ2h0eWVsbG93JykpCikKCnRhYmxlCgpgYGAKCiMKSSBzd2l0Y2hlZCBvdXQgRGFuaWVsIEpvbmVzIGZvciBhIGZldyBvdGhlciBRQnMgKFJ1c3NlbGwgV2lsc29uLCBUb20gQnJhZHksIEFhcm9uIFJvZGdlcnMgYW5kIERyZXcgTG9jaykgdG8gbWFrZSBzdXJlIGRpZmZlcmVudCBRQnMgaGFkIGRpc3RpbmN0IGVub3VnaCBwbG90cyB0byBiZSBtYWtpbmcgb2JzZXJ2YXRpb25zLgpgYGB7cn0KcXVhcnRlcmJhY2tfZHJvcGJhY2tzIDwtIHBicCAlPiUKICBtdXRhdGUoCiAgICBwYXNzZXIgPSBjYXNlX3doZW4oCiAgICAgIHBhc3NlciA9PSAnRC5Kb25lcycgfiAnRGFuaWVsIEpvbmVzJywKICAgICAgcGFzc2VyICE9ICdELkpvbmVzJyB+ICdPdGhlciBRQnMnCiAgICAgICksCiAgICBwYXNzZXIgPSBmYWN0b3IocGFzc2VyKQogICkgJT4lCiAgZmlsdGVyKGNwICE9ICdOQScsIHNlYXNvbiA9PSAyMDIwKSAlPiUKICBzZWxlY3QoY3AsIGludGVyY2VwdGlvbiwgcGFzc2VyLCB3ZWVrKQoKaW50ZXJjZXB0aW9uc19vbmx5IDwtIHF1YXJ0ZXJiYWNrX2Ryb3BiYWNrcyAlPiUKICBmaWx0ZXIoaW50ZXJjZXB0aW9uID09IDEsIHBhc3NlciA9PSAnRGFuaWVsIEpvbmVzJykKCnF1YXJ0ZXJiYWNrX2Ryb3BiYWNrcyAlPiUKICBnZ3Bsb3QoYWVzKHg9IGNwLCBmaWxsID0gcGFzc2VyKSkgKwogIGdlb21fZGVuc2l0eShhbHBoYSA9IC43KSArCiAgZ2VvbV9ydWcoZGF0YSA9IGludGVyY2VwdGlvbnNfb25seSwgYWVzKHggPSBjcCwgeSA9IDAsIGNvbG9yID0gcGFzc2VyKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9qaXR0ZXIoaGVpZ2h0ID0gMCksIHNob3cubGVnZW5kID0gRiwgbGVuZ3RoID0gdW5pdCgwLjA1LCAibnBjIikpICsKICBnZ3RoZW1lczo6dGhlbWVfZml2ZXRoaXJ0eWVpZ2h0KCkgKwogIHRoZW1lKAogICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KGZhY2UgPSAiYm9sZCIpLAogICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dCgpCiAgICApICsKICBsYWJzKAogICAgeCA9ICJDb21wbGV0aW9uIFByb2JhYmlsaXR5IiwKICAgIHkgPSAiRGVuc2l0eSIsCiAgICB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgRGFuaWVsIEpvbmVzJyBjb21wbGV0aW9uIHByb2JhYmlsaXR5XG5jb21wYXJlZCB0byB0aGUgcmVzdCBvZiB0aGUgbGVhZ3VlIiwKICAgIHN1YnRpdGxlID0gIkludGVyY2VwdGlvbnMgYXJlIHJlcHJlc2VudGVkIGFzIHJlZCB0aWNrIG1hcmtzIG9uIHRoZSB4LWF4aXMiLAogICAgY2FwdGlvbiA9ICJEYXRhOiBAbmZsZmFzdFIgfCBQbG90OiBATGF1cmFTdGlja2VsbHMiCiAgKQoKYGBgCgojCkEgbGluZWFyIG1vZGVsIHVzaW5nIGxlYWd1ZSB3aWRlIGNvbXBsZXRpb24gcHJvYmFiaWxpdHkgdG8gcHJlZGljdCBpbnRlcmNlcHRpb25zLiBJIGRpZG4ndCBkbyBhbnkgcHJlZGljdGl2ZSBhbmFseXNpcywgc28gSSBkb24ndCBleHBlY3QgdGhlc2UgbW9kZWxzIHRvIHBlcmZlY3RseSBwcmVkaWN0IGZ1dHVyZSBpbnRlcmNlcHRpb25zLiBJIHdhcyB1c2luZyB0aGVtIG1vcmUgdG8gdW5kZXJzdGFuZCB0aGUgcGFzdCByZWxhdGlvbnNoaXAgYmV0d2VlbiBjb21wbGV0aW9uIHByb2JhYmlsaXR5IGFuZCBpbnRlcmNlcHRpb25zIHdpdGggYSBZLWludGVyY2VwdC4KYGBge3J9CnBhc3NlcnMgPC0gcGJwMjAgJT4lCiAgZmlsdGVyKHBhc3NlciAhPSAnTkEnLCBjcCAhPSAnTkEnKQpwYXNzZXJzX21vZGVsIDwtIGxtKHBhc3NlcnMkaW50ZXJjZXB0aW9uIH4gcGFzc2VycyRjcCkKc3VtbWFyeS5sbShwYXNzZXJzX21vZGVsKQpgYGAKCiMKQSBsaW5lYXIgbW9kZWwgdXNpbmcgRGFuaWVsIEpvbmVzJyBjb21wbGV0aW9uIHByb2JhYmlsaXR5IHRvIHByZWRpY3QgaW50ZXJjZXB0aW9ucy4KYGBge3J9CmRhbmllbF9qb25lcyA8LSBwYnAyMCAlPiUKICBmaWx0ZXIocGFzc2VyID09ICdELkpvbmVzJywgY3AgIT0gJ05BJykKZGFuaWVsX2pvbmVzX21vZGVsIDwtIGxtKGRhbmllbF9qb25lcyRpbnRlcmNlcHRpb24gfiBkYW5pZWxfam9uZXMkY3ApCnN1bW1hcnkubG0oZGFuaWVsX2pvbmVzX21vZGVsKQpgYGAKCiMKR3JhcGhpbmcgdGhlIHR3byBsaW5lYXIgbW9kZWxzIGFnYWluc3QgZWFjaG90aGVyLgpgYGB7cn0KcGFzc2VycyRtb2RlbCA8LSAiTGVhZ3VlIEF2ZXJhZ2UiCmRhbmllbF9qb25lcyRtb2RlbCA8LSAiRGFuaWVsIEpvbmVzIgoKbGluZWFyX21vZGVscyA8LSByYmluZChwYXNzZXJzLCBkYW5pZWxfam9uZXMpCgpnZ3Bsb3QobGluZWFyX21vZGVscywgYWVzKHggPSBjcCwgeSA9IGludGVyY2VwdGlvbiwgZ3JvdXA9bW9kZWwsIGNvbG9yID1tb2RlbCkpICsgCiAgc3RhdF9zbW9vdGgobWV0aG9kID0gImxtIiwgZ2VvbSA9ICJsaW5lIiwgYWxwaGEgPSAwLjUsIHNlID0gRkFMU0UsIHNpemUgPSAxKSArCiAgZ2d0aGVtZXM6OnRoZW1lX2ZpdmV0aGlydHllaWdodCgpICsKICB0aGVtZSgKICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgbGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpLAogICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChmYWNlID0gImJvbGQiKSwKICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoKQogICAgKSArCiAgbGFicygKICAgIHggPSAiQ29tcGxldGlvbiBQcm9iYWJpbGl0eSIsCiAgICB5ID0gIkludGVyY2VwdGlvbiBQcm9iYWJpbGl0eSIsCiAgICB0aXRsZSA9ICJDb3JyZWxhdGlvbiBiZXR3ZWVuIGNvbXBsZXRpb24gcHJvYmFiaWxpdHlcbmFuZCBpbnRlcmNlcHRpb25zIiwKICAgIHN1YnRpdGxlID0gIiIsCiAgICBjYXB0aW9uID0gIkRhdGE6IEBuZmxmYXN0UiB8IFBsb3Q6IEBMYXVyYVN0aWNrZWxscyIKICApCmBgYAoKIwpUaGlzIHRhYmxlIGNhbGN1bGF0aW5nIHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIGNvbXBsZXRpb24gcHJvYmFiaWxpdHkgYW5kIGludGVyY2VwdGlvbnMgZG9lc24ndCBtZWFuIG11Y2ggd2l0aG91dCBsb29raW5nIGF0IHRoZSB5LWludGVyY2VwdHMsIGJ1dCB0aGUgcmVzdWx0cyBwcm92aWRlIHNvbWUgaW50ZXJlc3RpbmcgaW5zaWdodHMsIHdoaWNoIGNvdWxkIGJlIGFuIGludGVyZXN0aW5nIGFyZWEgZm9yIGZ1dHVyZSBleHBsb3JhdGlvbi4KYGBge3J9CnBicDIwICU+JQogIGZpbHRlcihwYXNzZXIgIT0gJ05BJywgY3AgIT0gJ05BJykgJT4lCiAgZ3JvdXBfYnkocGFzc2VyKSAlPiUKICBzdW1tYXJpemUoCiAgICBjb3IgPSBjb3IoY3AsIGludGVyY2VwdGlvbiksIAogICAgcGxheXMgPSBuKCksIAogICkgJT4lCiAgZmlsdGVyKHBsYXlzID49IDEwMCkgJT4lCiAgYXJyYW5nZShjb3IpICU+JQogIHVuZ3JvdXAoKQpgYGAKCiMKIwo=